﻿using System;
using System.Threading;

namespace ImageFan.Auxiliary
{
    internal class TasksDispatcher
    {
        public TasksDispatcher(WaitCallback globalTask, WaitCallback individualTask, int tasksCount)
        {
            _globalTask = globalTask;
            _individualTask = individualTask;
            _tasksCount = tasksCount;

            _isStopped = true;
        }

        public void Start()
        {
            _dispatcherIsActive = true;
            
            ThreadPool.QueueUserWorkItem(WorkerThreadLoopMethod);
        }

        public void Stop()
        {
            _dispatcherIsActive = false;
        }

        public bool IsStopped
        {
            get { return _isStopped; }
        }


        #region Private

        private static readonly int ProcessorCount;
        private static AutoResetEvent[] IndividualTaskEvents;

        private WaitCallback _globalTask;
        private WaitCallback _individualTask;
        private int _tasksCount;

        private volatile bool _dispatcherIsActive;
        private volatile bool _isStopped;

        private void WorkerThreadLoopMethod(object state)
        {
            try
            {
                _isStopped = false;
                
                for (var i = 0; (i < _tasksCount) && (_dispatcherIsActive); i += ProcessorCount)
                {
                    int j;

                    for (j = 0; (j < ProcessorCount) && (i + j < _tasksCount) && (_dispatcherIsActive); j++)
                        _globalTask(i + j);

                    for (j = 0; (j < ProcessorCount) && (i + j < _tasksCount) && (_dispatcherIsActive); j++)
                        ThreadPool.QueueUserWorkItem(IndividualTaskWrapper, new TaskParameter(i + j, j));

                    for (j = 0; (j < ProcessorCount) && (i + j < _tasksCount) && (_dispatcherIsActive); j++)
                        IndividualTaskEvents[j].Set();
                }
            }
            catch
            {
            }
            finally
            {
                _isStopped = true;
            }
        }

        private void IndividualTaskWrapper(object state)
        {
            try
            {
                TaskParameter taskParam = ((TaskParameter)state);

                IndividualTaskEvents[taskParam.ThreadIndex].WaitOne();
                _individualTask(taskParam.MainIndex);
            }
            catch
            {
            }
        }

        #endregion


        static TasksDispatcher()
        {
            ProcessorCount = Environment.ProcessorCount;

            IndividualTaskEvents = new AutoResetEvent[ProcessorCount];
            for (var i = 0; i < ProcessorCount; i++)
                IndividualTaskEvents[i] = new AutoResetEvent(false);
        }
    }
}
